package org.novelhibernate.support.logging;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * The factory used to create logging proxy within Spring managed environment
 * 
 * @author Tao Chen
 * 
 */
public class SpringBeanFactory {

	public Object create(String classInterface, String clazz,
			boolean isUseProxy, Map<String, Object> map) throws Exception {

		Object object = Class.forName(clazz).newInstance();

		// loading the parameters
		if (null != map) {

			String name = null;
			for (String key : map.keySet()) {

				name = "set" + convertToMethodName(key);
				// loop and find the target method
				for (Method method : object.getClass().getMethods())
					if (method.getName().equals(name)
							&& method.getParameterTypes().length == 1) {
						// check if it is proper for the interface
						if (method.getParameterTypes()[0].isInterface()) {

							for (Class<?> i : map.get(key).getClass()
									.getInterfaces()) {

								if (i == method.getParameterTypes()[0]) {
									method.invoke(object, map.get(key));
									name = null;
									break;

								}

							}
							// check if it is a sub class
						} else if (method.getParameterTypes()[0].isInstance(map
								.get(key))) {

							method.invoke(object, map.get(key));
							name = null;

						}

						if (null == name)
							break;

					}
			}
		}
		return Class.forName(classInterface).cast(
				NativeLogFactory.getInstance().produceLogPointBase(object,
						(isUseProxy) ? null : Class.forName(clazz)));
	}

	/**
	 * Convert the alias to method (with the first letter capital)
	 * 
	 * @param name
	 *            the target
	 * @return the converted name
	 */
	private String convertToMethodName(String name) {

		int start = name.lastIndexOf(".");
		if (-1 == start)
			return nameToMethod(name);
		else
			return name.substring(start + 1);

	}

	/**
	 * Extract the name of type from a filed to a path of method (e.g. name to
	 * set or get should be added afterward of course)
	 * 
	 * @param name
	 *            the target name
	 * @return the name with first letter capital
	 */
	private String nameToMethod(String name) {

		StringBuffer buffer = new StringBuffer(name);
		buffer.setCharAt(0, Character.toUpperCase(buffer.charAt(0)));

		return buffer.toString();
	}
}
